#ifndef __ATMOS_MSClient_h__
#define __ATMOS_MSClient_h__

#include "ATMOS_Common.h"
#include "ATMOS_PacketListener.h"
#include "ATMOS_PacketID.h"
#include "ATMOS_NetworkConnectionInfo.h"

namespace ATMOS {

//! Client class for registration and interaction with the MasterServer
/*! The MSClient class allows an application register itself with the MasterServer.  Each MSClient
 * instance represents either a game server or game client, and the MasterServer is responsible for
 * matching clients with open servers.
 * 
 * Classes that wish to monitor the network events that are sent to the MSClient must provide their
 * own PacketListener-derived class, then register that listener with the MSClient's NetworkManager.
 */
class AtmosExport MSClient : 
	public PacketListener, 
	public AutoHandler<MSClient,Packet*,void,PacketID>
{		
public:
	/*!
	 \param representsGameServer whether this MSClient represents a game server or game client
	 \param clientName the name of the MSClient
	 \param masterServerInfo info for the connection to the MasterServer
	 \param localGamePort the port for the local game connection to listen on
	 */
	MSClient( bool representsGameServer, const std::string &clientName,
		const NetworkConnectionInfo &masterServerInfo, int localGamePort );
	virtual ~MSClient();
		
	//! updates the underlying NetworkManagerClient
	void update();
				
	//! get the locally stored list of servers, refresh with MSClient::sendMSRequestGameServerList
	const StringVector &getServersList() const;
	//! send a request to connect to a given game server (which means that this instance is a client)
	void requestConnectionToGameServer( const std::string &serverGUID );
	//! check if this MSClient has received permission to connect to a game server (which means that this instance is a client)
	bool readyForGameConnection() const;
	//! only valid when MSClient::readyForGameConnection is true, this provides the info for the game connection
	NetworkConnectionInfo getGameConnectionInfo() const;
	
	//! check whether this MSClient is connected to the MasterServer
	bool connectedToMasterServer();		
	//! get the GUID of the MSClient on the MasterServer connection
	std::string getGUID();
		
	// send ATMOS packets
	//----------------------------------------------------------------------------------------------
	void sendMSPacket( Packet *packet );		
	void sendMSRegisterClient();
	void sendMSUnregisterClient();
	void sendMSRequestGameServerList();
	void sendGameServerConnectRequest( const std::string &desiredServerGUID );
	void sendGameConnectionEstablished( const std::string &connectedServerGUID );		
	void sendGameConnectionFailed( const std::string &unconnectedServerGUID );
	
	// ATMOS packet handlers
	//----------------------------------------------------------------------------------------------
	virtual void onAtmosPacket( Packet *packet );
	virtual void onDisconnectionNotification( const std::string &senderGUID );
	virtual void onAlreadyConnected( const std::string &senderGUID );
	virtual void onIncompatibleProtocolVersion( const std::string &senderGUID );
	virtual void onRemoteDisconnectionNotification( const std::string &senderGUID );
	virtual void onRemoteConnectionLost( const std::string &senderGUID );
	virtual void onNewIncomingConnection( const std::string &senderGUID );
	virtual void onConnectionBanned( const std::string &senderGUID );
	virtual void onConnectionAttemptFailed( const std::string &senderGUID );
	virtual void onNoFreeIncomingConnections( const std::string &senderGUID );
	virtual void onInvalidPassword( const std::string &senderGUID );
	virtual void onConnectionLost( const std::string &senderGUID );
	virtual void onConnectionRequestAccepted( const std::string &senderGUID );
	virtual void onUnknownPacket( const std::string &senderGUID );

protected:		
	// RAKNET packet handlers
	//----------------------------------------------------------------------------------------------
	void onConnectionEstablished( Packet *packet );
	void onConnectionFailed( Packet *packet );
	
	// MASTER SERVER packet handlers
	//----------------------------------------------------------------------------------------------
	void onMSPacket( Packet *packet );
	void onReceiveServerList( Packet *packet );
	void onGameConnectionApproved( Packet *packet );
	void onGameConnectionDenied( Packet *packet );		
	
private:
	//! whether this MSClient represents a game server
	bool mRepresentsGameServer;
	//! the name of the MSClient (regardless of whether it represents a game server or game client)
	std::string mClientName;
	//! the list of servers last received from the MasterServer
	StringVector mRemoteServers;
	//! whether this MSClient is ready to connect to a game server (meaning it's a game client)
	bool mReadyForGameConnection;
	//! info for the game connection, NOT the MasterServer
	NetworkConnectionInfo mGameConnectionInfo;
	//! whether this MSClient is currently connected to the MasterServer
	bool mConnectedToMasterServer;
	//! the GUID for the MasterServer connection
	std::string mServerGUID;
	//! the port for the local game connection to listen on
	int mLocalGamePort;
};

} // end namespace ATMOS

#endif